package com.cysoft.starter.repeat.core.validata.impl;

import com.cysoft.starter.repeat.core.model.RepeatInfo;
import com.cysoft.starter.repeat.core.validata.RepeatValidata;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 玖零
 * @version V0.0.1
 * @project cysoft-spring-boot-starter-repeat
 * @package com.cysoft.starter.repeat.core.validata.impl
 * @date 2025-03-02 17:18
 * @desc
 */
@Slf4j
public class LocalRepeatValidata implements RepeatValidata {

    /**
     * 用于存储已经处理过的请求及其过期时间戳
     * 键为请求的唯一标识，值为该请求的过期时间戳（毫秒）
     */
    private static final ConcurrentHashMap<String, Long> cache = new ConcurrentHashMap<>();

    /**
     * 验证请求是否为重复请求
     *
     * @param repeatInfo 包含请求相关信息的对象，如请求的唯一键、过期时间和时间单位
     * @return 如果是重复请求返回 true，否则返回 false
     */
    @Override
    public boolean validataRepeat(RepeatInfo repeatInfo) {
        // 获取请求的唯一键，用于标识该请求
        String requestKey = repeatInfo.getRequestKey();
        // 获取当前系统时间，单位为毫秒
        long currentTime = System.currentTimeMillis();

        // 从缓存中获取该请求键对应的过期时间戳
        Long expireTimestamp = cache.get(requestKey);

        if (expireTimestamp != null) {
            // 如果缓存中存在该请求键，检查其是否过期
            if (currentTime < expireTimestamp) {
                // 如果当前时间小于过期时间戳，说明该请求还在有效期内，判定为重复请求
                return true;
            } else {
                // 如果已过期，从缓存中移除该请求键，释放缓存空间
                cache.remove(requestKey);
            }
        }

        // 计算新的过期时间戳，当前时间加上配置的过期时间（转换为毫秒）
        long newExpireTimestamp = currentTime + repeatInfo.getExpireTimeUnit().toMillis(repeatInfo.getExpireTime());

        // 将新的过期时间戳存入缓存，覆盖旧值（如果存在）
        cache.put(requestKey, newExpireTimestamp);

        // 首次存入该请求键，说明不是重复请求，返回 false
        return false;
    }
}
